package com.winner.data.controller;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;

import javax.annotation.Resource;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.winner.data.exception.R;
import com.winner.data.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * 多线程控制层
 *
 * @author wangxinle5
 * @since 2023-01-03
 */
@Slf4j
@RestController
@RequestMapping("/")
public class MultiThreadController extends BaseController {

    @Resource
    UserService userService;

    // CountDownLatch是一个同步工具类，它允许一个或多个线程一直等待，直到其他线程执行完后再执行, Java8设计了CompletableFuture这个类
    // localhost:8080/async 如下打印结果是无序的, 则说明异步多线程生效了
    @GetMapping("/async")
    public R async() throws InterruptedException {
        // 信号量Semaphore(信号量是用来限制并发访问某一共享资源的线程的数量的。这里的共享资源可以比如是：一个文件，CPU等。信号量可以通过acquire和release函数变化)
        // 计数栓CountDownLatch(是用来保证某个线程可以在其他一些线程完成之后开始执行的)  https://blog.csdn.net/weixin_34360651/article/details/90221277
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            // 基于@Async无返回值调用 countDownLatch.countDown();方法必须在业务代码里写
            userService.executeAsyncTask(i, countDownLatch);
        }
        countDownLatch.await(); //等待锁存器
        // 等待现场走完
        System.out.println("await finished.");
        return success();
    }

    // localhost:8080/asyncWithReturn
    // 基于@Async有返回值的调用 https://blog.csdn.net/qq_35387940/article/details/120866062
    // 有些业务场景 优化 就需要 并行去计算, 等并行的线程结果都出来((取决于耗时最多的那个线程), 在主线程加工数据返回给前端
    @GetMapping("/asyncWithReturn")
    public R asyncWithReturn() throws InterruptedException, ExecutionException {
        CompletableFuture<String> a = userService.pullDataA();
        CompletableFuture<String> b = userService.pullDataB();
        CompletableFuture<String> c = userService.pullDataC();
        // 等待收集 a b c 3个返回值
        CompletableFuture.allOf(a, b, c).join();
        log.info("asyncWithReturn 接口返回值是: " + a.get() + b.get() + c.get());
        return success("asyncWithReturn 接口返回值是: " + a.get() + b.get() + c.get());
    }

}
